/*

    This file is part of Blue Violin.

    Blue Violin is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Blue Violin is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero Public License for more details.

    You should have received a copy of the GNU Affero Public License
    along with Blue Violin.  If not, see <http://www.gnu.org/licenses/>.

    Blue Violin  Copyright (C) 2008  Blue Violin, Inc. & Josh Watts <josh.watts@blueviolin.org>
	For more information, visit http://www.blueviolin.org/

    This program comes with ABSOLUTELY NO WARRANTY.
*/


#include "stdafx.h"
#include "Util.h"
#include <iostream>
#include <string.h>


char* Util::Base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
	char *szBuff = new char[in_len * 2];
	char szBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	std::string sRet = "";
	int i = 0;
	int j = 0;
	int nBuffIndex = 0;
	unsigned char szChars[3];
	unsigned char szEncoded[4];
	long nRemaining = in_len;
	long nIndex = 0;
	long nCopy = 0;
	long nLineLen = 0;

	memset((void*)szBuff, 0, sizeof(char) * in_len * 2);
	while (1) 
	{
		if (0 >= nRemaining)
		{
			break;
		}
		for (i = 0;
			 i < 3;
			 ++i)
		{
			if (0 >= nRemaining - i)
			{
				szChars[i] = 0;
			}
			else
			{
				szChars[i] = *(bytes_to_encode++);
			}
		}
		szEncoded[0] = (szChars[0] & 0xfc) >> 2;
		szEncoded[1] = ((szChars[0] & 0x03) << 4) + ((szChars[1] & 0xf0) >> 4);
		szEncoded[2] = ((szChars[1] & 0x0f) << 2) + ((szChars[2] & 0xc0) >> 6);
		szEncoded[3] = szChars[2] & 0x3f;
		nCopy = 4;
		switch (nRemaining)
		{
			case 1:
				nCopy = 2;
				break;
				
			case 2:
				nCopy = 3;
				break;
		}
		for (i = 0;
			 i < nCopy;
			 ++i)
		{
			szBuff[nBuffIndex++] = szBase64Chars[szEncoded[i]];
		}
		for (i = nCopy;
			 i < 4;
			 ++i)
		{
			szBuff[nBuffIndex++] = '=';
		}
		nRemaining -= 3;
	}
	return szBuff;
}


// derived from 
// http://www.codeguru.com/cpp/i-n/internet/http/article.php/c12759/
char* Util::UriEncode(char* szSrc, int nLength)
{
// Only alphanum is safe.
	const char SAFE[256] =
		{
			/*      0 1 2 3  4 5 6 7  8 9 A B  C D E F */
			/* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
    
			/* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
			/* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
			/* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
			/* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
    
			/* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
    
			/* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
			/* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
		};
   const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
   const char * pSrc = (const char *)szSrc;
   const char *SRC_END = pSrc + nLength;
   char *szStart = new char[nLength * 3];
   char *pEnd = szStart;
   char *szReturn = NULL;
   memset((void*)szStart, 0, sizeof(char) * (nLength * 3));
   for (int i = 0; 
		i < nLength;
		++i, ++pSrc)
   {
      if (SAFE[*pSrc])
         *pEnd++ = *pSrc;
      else
      {
         // escape this char
         *pEnd++ = '%';
         *pEnd++ = DEC2HEX[*pSrc >> 4];
         *pEnd++ = DEC2HEX[*pSrc & 0x0F];
      }
   }
   int nTempLength = strlen(szStart);
   szReturn = new char[strlen(szStart) + 1];
   memset((void*)szReturn, 0, sizeof(char) * (strlen(szStart) + 1));
   strcpy(szReturn, szStart);
   delete []szStart;
   return szReturn;
}


// static const std::string base64_chars = 
// 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
// 	"abcdefghijklmnopqrstuvwxyz"
// 	"0123456789+/";

// static inline bool is_base64(unsigned char c) {
// 	return (isalnum(c) || (c == '+') || (c == '/'));
// }

// std::string base64_decode(std::string const& encoded_string) {
// 	int in_len = encoded_string.size();
// 	int i = 0;
// 	int j = 0;
// 	int in_ = 0;
// 	unsigned char char_array_4[4], char_array_3[3];
// 	std::string ret;

// 	while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
// 		char_array_4[i++] = encoded_string[in_]; in_++;
// 		if (i ==4) {
// 			for (i = 0; i <4; i++)
// 				char_array_4[i] = base64_chars.find(char_array_4[i]);

// 			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
// 			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
// 			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

// 			for (i = 0; (i < 3); i++)
// 				ret += char_array_3[i];
// 			i = 0;
// 		}
// 	}

// 	if (i) {
// 		for (j = i; j <4; j++)
// 			char_array_4[j] = 0;

// 		for (j = 0; j <4; j++)
// 			char_array_4[j] = base64_chars.find(char_array_4[j]);

// 		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
// 		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
// 		char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

// 		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
// 	}

// 	return ret;
// }
